/*
 * backTrack.cpp
 *
 *  Created on: 2011-09-10
 *      Author: pawel
 */
#include"../algorithms.h"
#include"backTrack.h"
#include"alignStrings.h"
#include"../enumTypes.h"
#include"../alignContainerV.h"
#include <string.h>
#include <pthread.h>
#include<limits.h>
#include <pthread.h>
#include<limits.h>
#include<stdint.h>
#include<sys/param.h>
#include<string.h>
//#include<list>
#include<memory>
#include<Bpp/Seq/Sequence.h>
#include"../align.h"
#include"../smart2DArray.h"
//#include<stdio.h>
#include<assert.h>
//#define SIM_IDE(a, b) (((a) == (b)) ? (ALIGN_IDENTITY) : (ALIGN_SIMILARITY))
int  btrack::backTrack(optAlgParam &param, const cell &traceCell,optAlgThreadParam &th){
	try{
	btrack::alignStrings a(MAX(param.dirMatrix.rows,param.dirMatrix.cols));
	smart2DArray<char> smartQueryCString(1,param.dirMatrix.rows);
	char *queryCString =(smartQueryCString.getPtr())[0];
	smart2DArray<char> smartDbCString(1,param.dirMatrix.cols);
	char *dbCString = (smartDbCString.getPtr())[0];
	memcpy((void*)queryCString,(void*)((param.querySeqPtr->toString()).c_str()),param.dirMatrix.rows*sizeof(char));
	memcpy((void*)dbCString,(void*)((param.dbSeqPtr->toString()).c_str()),param.dirMatrix.cols*sizeof(char));

	if(th.btrace){
	rTrack(param.dirMatrix,traceCell,a,queryCString,dbCString);
	}

	align *alPtr;
	std::auto_ptr<align> smartAlign(new align(param.querySeqPtr,param.dbSeqPtr,a,traceCell.maxscore));
	alPtr = smartAlign.get();

	pthread_mutex_lock(th.alignContainerPtr->getMutex());
	try{
		th.alignContainerPtr->pushAlign(alPtr);
		smartAlign.release();
	}catch(std::exception& e){
		pthread_mutex_unlock(th.alignContainerPtr->getMutex());
		throw;
	}
	pthread_mutex_unlock(th.alignContainerPtr->getMutex());

	}catch(std::exception& e){
		throw;
	}
	return 0;
}
int btrack::rTrack(const directionMatrix &matrix,cell traceCell,btrack::alignStrings& alignS,
		const char* qu,const char* db){

	size_t row = traceCell.maxRow;
	size_t col = traceCell.maxCol;

	char value = matrix.matrix[row][col];
	alignS.setStop(row -1,col -1);
	char que,dba;
	while(true){

		if(((int)row -1)>=0)que = qu[row-1];
		if(((int)col -1)>=0)dba = db[col-1];
			if(value & DR_STOP){
				break;
			}
			else if(value & DR_DIAG){
				alignS.insert(que,dba,value);
				if(col>0)col--;
				if(row>0)row--;
			}
			else if(value & DR_UP){
				alignS.insert(que,dba,value);

				if(row>0)row--;
			}
			else if(value & DR_LEFT){
				alignS.insert(que,dba,value);

				if(col>0)col--;
			}else{
				break;
			}

			value = matrix.matrix[row][col];
			alignS.setStart(row,col);
	}
	return 0;
}
